package org.xiaojinlong.thread;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.*;

/**
 * @author Jin Long
 *         2015/10/10
 */
public class TestBlockingQueues {
    static void getKey() {
        try {
            new BufferedReader(
                    new InputStreamReader(System.in)).readLine();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    static void getKey(String message) {
        System.out.println(message);
        getKey();
    }

    static void test(String msg, BlockingQueue<LiftOff> queue) {
        System.out.println(msg);
        LiftOffRunner runner = new LiftOffRunner(queue);
        Thread t = new Thread(runner);
        Thread q = new Thread(new LiftOffAdder(queue));
        q.start();
        t.start();
        getKey("Press 'Enter' (" + msg + ")");
        q.interrupt();
        t.interrupt();
        System.out.println("Finished " + msg + " test");
    }

    public static void main(String[] args) {
        test("LinkedBlockingQueue", new LinkedBlockingQueue<>());
        test("ArrayBlockingQueue", new ArrayBlockingQueue<>(3));
        test("SynchronousQueue", new SynchronousQueue<>());

    }
}

class LiftOffRunner implements Runnable {
    private BlockingQueue<LiftOff> rockets;

    public LiftOffRunner(BlockingQueue<LiftOff> queue) {
        rockets = queue;
    }

    public void add(LiftOff rocket) {
        try {
            rockets.put(rocket);
        } catch (InterruptedException e) {
            System.out.println("Interrupted during put()");
        }
    }

    @Override
    public void run() {
        try {
            while (!Thread.interrupted()) {
                LiftOff rocket = rockets.take();
                rocket.run();
            }
        } catch (InterruptedException e) {
            System.out.println("Waking from take()");
        }
        System.out.println("Exiting LiftOffRunner");
    }
}

class LiftOffAdder implements Runnable {
    private BlockingQueue<LiftOff> rockets;

    public LiftOffAdder(BlockingQueue<LiftOff> rockets) {
        this.rockets = rockets;
    }

    @Override
    public void run() {
        try {
            while (!Thread.interrupted()) {
                rockets.put(new LiftOff(5));
                TimeUnit.SECONDS.sleep(1);
            }
        } catch (InterruptedException e) {
            System.out.println("LiftOffAdder interruppted");
        }
        System.out.println("LiftOffAdder exit");
    }
}